package com.thientan.controller

import grails.converters.JSON

import java.text.SimpleDateFormat

import org.hibernate.criterion.CriteriaSpecification
import org.hibernate.transform.Transformers

import com.thientan.export.ExportType
import com.thientan.model.ChiTietThuChi
import com.thientan.model.DuLieuHeThong
import com.thientan.model.HopDong
import com.thientan.model.ThongKePhieuThu
import com.thientan.model.enums.LoaiChiTietThuChi
import com.thientan.model.enums.TrangThaiHopDong
import com.thientan.service.ThongKePhieuThuService
import com.thientan.service.TimHopDongService
import com.thientan.utils.Constants
import com.thientan.utils.Utility

class TimHopDongController extends HopDongController {
	TimHopDongService timHopDongService
	ThongKePhieuThuService thongKePhieuThuService
	
	@Override
	public Object getDomainService() {
		timHopDongService
	}
	
	private List<String> getRenderedProps() {
		[
			"maHd",
			"maDt",
			"maTn",
			"maNv1",
			"maNv2",
			"khHoTen",
			"trangThaiText",
			"giaTri",
			"tienDaThu",
			"tienConLai"
		]
	}

	private List<String> getMorePropsForExport() {
		[
			"khDchi",
			"khDt",
			"khPxa",
			"khQhuyen",
			"khTpho",
			"ngayBanText",
			"tienTraTruoc",
			"tienGiamGia",
			"liDoGiamGia"
		]
	}

	def search = {
		def hds = doQuery() // hds here is a PagedResultList instance
		Map data = listAsMap(extractPropertiesAsMapsWithOrderNumber(hds, renderedProps))
		data.putAt("count", hds.totalCount)
		render data as JSON
	}

	protected Map buildExportData(Map exportParams) {
		def sdfDateTo = new java.text.SimpleDateFormat(Constants.DEFAULT_DATE_FORMAT)
		List hds = doQuery()
		if (!hds) {
			return ["data" : null,
				"tongSoHd" : "0",
				"ngayXuat" : sdfDateTo.format(new Date()),
				"thoiGian" : ""]
		}
		Map relatedData = getRelatedChiTietThuChi(hds*.id)
		List hdData =  extractPropertiesAsMapsWithOrderNumber(hds, renderedProps + morePropsForExport, true)
		hdData = hdData.collect {
			Long hdId = it["id"]
			Map additionalMap = ["denDt" : null, "denNv" : null, "denCty" : null, "tienTraKhach" : null, "tienKhauHao" : null]
			if (relatedData.get(hdId)) {
				List chiTiets = relatedData.get(hdId)
				chiTiets.each {
					String value = it[2] != null ? Utility.moneyFormat(it[2]) : ""
					switch (it[1]) {
						case LoaiChiTietThuChi.DEN_DT:
							additionalMap["denDt"] = value
							break
						case LoaiChiTietThuChi.DEN_NV:
							additionalMap["denNv"] = value
							break
						case LoaiChiTietThuChi.DEN_CTY:
							additionalMap["denCty"] = value
							break
						case LoaiChiTietThuChi.TRA_KHACH:
							additionalMap["tienTraKhach"] = value
							break
						case LoaiChiTietThuChi.KHAU_HAO:
							additionalMap["tienKhauHao"] = value
							break
						default:
							break
					}
				}
			}
			it + additionalMap
		}

		def sdfToDate = new java.text.SimpleDateFormat(Constants.TO_DATE_FORMAT)
		String fromDate = params.ngayBanFrom ? sdfDateTo.format(sdfToDate.parse(params.ngayBanFrom)) : ""
		String toDate = params.ngayBanTo ? sdfDateTo.format(sdfToDate.parse(params.ngayBanTo)) : 
										   message(code : "default.thientan.messages.now", args : null)
		return ["data" : hdData, 
				"tongSoHd" : hds.size().toString(), 
				"ngayXuat" : sdfDateTo.format(new Date()), 
				"thoiGian" : fromDate + " - " + toDate]
	}

	private Map getRelatedChiTietThuChi(List hdIds) {
		List cttcs = ChiTietThuChi.withCriteria {
			projections {
				property("hopDong.id")
				property("loaiChiTiet")
				property("soTien")
			}
			'in'("hopDong.id", hdIds)
		}
		Map result = [:]
		cttcs.each {
			Long hdId = it[0]
			List existData = result.get(hdId)
			if (existData) {
				existData << it
				result.put(hdId, existData)
			} else {
				result.put(hdId, [it])
			}
		}
		result
	}

	private def doQuery() {
		boolean isExport = actionName == "export"
		def criteria = isExport ? params : JSON.parse(params["criteria"])
		def hds = HopDong.createCriteria().list(max : (params["max"] ? params.int('max') : null), 
												offset : ( params["offset"] ? params.int('offset') : null)) {
			createAlias("khachHang", "kh", CriteriaSpecification.INNER_JOIN)
			createAlias("nvDoiTruong", "dt", CriteriaSpecification.LEFT_JOIN)
			createAlias("nvBan1", "nv1", CriteriaSpecification.INNER_JOIN)
			createAlias("nvBan2", "nv2", CriteriaSpecification.INNER_JOIN)
			createAlias("nvThuNgan", "tn", CriteriaSpecification.LEFT_JOIN)
			
			projections {
				if (params["isChangeThuNgan"] || params["isDongHd"]) {
					property("id")
				} else {
					property("maHd", "maHd")
					property("dt.maNv", "maDt")
					property("tn.maNv", "maTn")
					property("nv1.maNv", "maNv1")
					property("nv2.maNv", "maNv2")
					property("kh.hoTen", "khHoTen")
					property("trangThai", "trangThai")
					property("giaTri", "giaTri")
					property("tienDaThu", "tienDaThu")
					property("tienConLai", "tienConLai")
					if (isExport) {
						property("kh.diaChi", "khDchi")
						property("kh.dienThoai", "khDt")
						property("kh.phuongXa", "khPxa")
						property("kh.quanHuyen", "khQhuyen")
						property("kh.tinhThanh", "khTpho")
						property("ngayBan", "ngayBan")
						property("tienTraTruoc", "tienTraTruoc")
						property("tienGiamGia", "tienGiamGia")
						property("liDoGiamGia", "liDoGiamGia")
					}
				}
			}
				
			if (criteria["maHd"]) {
				like("maHd", criteria["maHd"])
			}

			if (criteria["nvDoiTruong-id"] == "NO_DT") {
				isNull("nvDoiTruong")
			} else if (criteria["nvDoiTruong-id"]) {
				eq("nvDoiTruong.id", Long.valueOf(criteria["nvDoiTruong-id"]))
			}

			if (criteria["nvBan-id"]) {
				or {
					eq("nvBan1.id", Long.valueOf(criteria["nvBan-id"]))
					eq("nvBan2.id", Long.valueOf(criteria["nvBan-id"]))
				}
			}

			if (criteria["nvThuNgan-id"] == "CTY") {
				isNull("nvThuNgan")
			} else if (criteria["nvThuNgan-id"]) {
				eq("nvThuNgan.id", Long.valueOf(criteria["nvThuNgan-id"]))
			}

			if (criteria["ngayBanFrom"]) {
				ge("ngayBan", new SimpleDateFormat(Constants.TO_DATE_FORMAT).parse(criteria["ngayBanFrom"]))
			}

			if (criteria["ngayBanTo"]) {
				le("ngayBan", new SimpleDateFormat(Constants.TO_DATE_FORMAT).parse(criteria["ngayBanTo"]))
			}

			if (criteria["kh-hoTen"]) {
				ilike("kh.hoTen", criteria["kh-hoTen"])
			}

			if (criteria["tinhThanh"]) {
				eq("kh.tinhThanh", DuLieuHeThong.findByMaDuLieu(criteria["tinhThanh"]).giaTri)
			}

			if (criteria["quanHuyen"]) {
				eq("kh.quanHuyen", DuLieuHeThong.findByMaDuLieu(criteria["quanHuyen"]).giaTri)
			}

			if (criteria["phuongXa"]) {
				eq("kh.phuongXa", DuLieuHeThong.findByMaDuLieu(criteria["phuongXa"]).giaTri)
			}
			
			if (criteria["daGiaoPhieu"] != "") {
				eq("daGiaoPhieu", Boolean.valueOf(criteria["daGiaoPhieu"]))
			}
			
			if (criteria["trangThai"]) {
				eq("trangThai", TrangThaiHopDong.valueOf(criteria["trangThai"]))
			} else {
				ne("trangThai", TrangThaiHopDong.DONG) // always exclude contracts whose status is 'DONG' if not specify explicitly
			}
			order("maHd")
			if (!params["isChangeThuNgan"] && !params["isDongHd"]) {
				resultTransformer(Transformers.aliasToBean(HopDong.class))
			}
		}
		hds
	}

	def changeThuNgan = {
		List<Long> ids = doQuery()
		def idThuNgan = params["idThuNgan"]
		if (idThuNgan == "CTY") {
			idThuNgan = null
		}
		Map result = [:]
		try {
			HopDong.executeUpdate("update HopDong hd set hd.nvThuNgan.id = ${idThuNgan} where id in (:ids)", [ids : ids])
			result = ["success" : true, numOfHd : ids.size()]
		} catch (Exception e) {
			log.error("Error occurred when assigning casher to contract: ", e)
			result = ["success" : false]
		}
		render result as JSON
	}
	
	def dongHd = {
		List<Long> ids = doQuery()
		Map result = [:]
		try {
			int numHd = HopDong.executeUpdate("update HopDong hd set hd.trangThai = '${TrangThaiHopDong.DONG.value}' " + 
						"where hd.id in (:ids) and hd.trangThai <> '${TrangThaiHopDong.DANG_TRA_GOP.value}'", [ids : ids])
			result = ["success" : true, numOfHd : numHd]
		} catch (Exception e) {
			log.error("Error occurred when closing contracts: ", e)
			result = ["success" : false]
		}
		render result as JSON
	}
	
	def giaoPhieuThu = {
		List<Long> ids = doQuery()
		Map result = [:]
		try {
			Long daGiaoPt = HopDong.countByIdInListAndDaGiaoPhieu(ids, true)
			if (daGiaoPt > 0) {
				result = ["success" : false, numOfHd : daGiaoPt]
			} else {
				Long numHd = HopDong.executeUpdate("update HopDong hd set hd.daGiaoPhieu = true " +
												  "where hd.id in (:ids)", [ids : ids])
				updateThongKePhieuThu(numHd)
				result = ["success" : true, "daGiaoPt" : true, numOfHd : numHd]
			}
		} catch (Exception e) {
			log.error("Error occurred when closing contracts: ", e)
			result = ["success" : false]
		}
		render result as JSON
	}
	
	private void updateThongKePhieuThu(Long numHd) {
		ThongKePhieuThu tkpt = thongKePhieuThuService.fetchOrCreateThongKePt()
		Long soPhieuCty = HopDong.countByNvThuNganIsNullOrDaGiaoPhieu(false)
		tkpt.soPhieuGiao += numHd
		tkpt.soPhieuCty = soPhieuCty
		thongKePhieuThuService.saveOrUpdate(tkpt)
	}
	
	@Override
	protected String getExportFileName(){
		"DanhSachHopDong"
	}
	
	@Override
	protected ExportType getExportType(){
		ExportType.XLS
	}
}
